using System;
using System.Collections;
using System.Xml.Serialization;

namespace WebApplication
{
	[Serializable]
	public class PublicCompanies : ICollection
	{
		private ArrayList  _aPublicCompanies;

		public PublicCompany this [int index]   // indexer declaration
		{ 
			get
			{
				return (PublicCompany) _aPublicCompanies[index];
			}

			set
			{
				_aPublicCompanies[index] = value;
			}
		}

		public PublicCompany this [string sIndex]   // indexer declaration
		{ 
			get
			{
				for (int i = 0; i < _aPublicCompanies.Count; i++)
				{
					PublicCompany company = _aPublicCompanies[i] as PublicCompany;

					if (company.Name == sIndex)
					{
						return (PublicCompany) _aPublicCompanies[i];	
					}
				}
				
				string sError = "Error: " + sIndex + " not found in public companies collection.";
				
				GameException	e; 
				e = new GameException (sError);
				throw (e);
			}
		}


		public void CopyTo(Array a, int index)
		{
			_aPublicCompanies.CopyTo(a, index);
		}
		public object SyncRoot
		{
			get{return this;}
		}
		public bool IsSynchronized
		{
			get{return false;}
		}

		public int Count
		{
			get
			{
				return _aPublicCompanies.Count;
			}
		}

		public PublicCompanies ()
		{
			_aPublicCompanies = new ArrayList ();
		}

		public void Add (System.Object PublicCompany)
		{
			_aPublicCompanies.Add (PublicCompany);
		}

		public void Add (PublicCompany Private)
		{
			_aPublicCompanies.Add (Private);
		}

		public void Remove (PublicCompany Private)
		{
			_aPublicCompanies.Remove (Private);
		}

		// IEnumerable Interface Implementation:

		public IEnumerator GetEnumerator() // non-IEnumerable version
		{
			return _aPublicCompanies.GetEnumerator ();
		}

		IEnumerator IEnumerable.GetEnumerator() // IEnumerable version
		{
			//			return (IEnumerator) new PrivateEnumerator(this);
			return _aPublicCompanies.GetEnumerator ();
		}
	}

	[Serializable]
	public class PublicCompany
	{
		public enum eStockAction
		{
			PayOut, Hold, SoldOut, Sold
		}

		private	bool	_bLoanTaken;
		private	bool	_bInterestPaid;
		private int		_tokensPlayed;
		private	Game	_game;		// current game object
		private Player	_owner;
		private string	_name;
		private int		_cash;
        private bool    _fullShares;
        private bool    _fullyFunded;
        private int     _lastDividend;
        private int     _escrow;	// money stored in escrow when RR reached dest
		private int		_parPrice;
		private int		_loans;
		private int		_tokens;
		private int		_index;
		private string	_home;
		private bool	_hasARoute;
		private	bool	_operated;
        private bool    _bCompanyAvailable; // if not closed or folded into CGR
        private bool    _canOperate;
		private	int		_RunningOrder;
		private	bool	_operatedThisOperatingRound;
		private string	_destination;
		private	bool	_needDestination;
		private	bool	_reachedDestination;
		private	bool	_foldIntoCGR;
        private bool    _foldIntoCGRActedOn;
        private string  _borrowedTrainName;
        private bool    _borrowedTrain;
        private bool    _borrowingTrain;
        private bool    _hadPermanantTrain;
        private Side    _startSide;	// For CV, indicates which side it starts on.
		private bool	_startSideSpecified;
		private bool	_deferredInitialTokenPlacement; // Can be set to true for THB and ERIE if no tile is in their home hex.
		private bool	_tunnelRights;
		private bool	_bridgeRights;
		private bool	_portRights;

		private HexVisit	_startOfRoute;		// The starting spot for a route.

		public bool DeferredInitialTokenPlacement
		{
			get { return _deferredInitialTokenPlacement; }
			set { _deferredInitialTokenPlacement = value; }
		}

		public bool	StartSideSpecified
		{
			get { return _startSideSpecified; }
			set { _startSideSpecified = value; }
		}

        public Side StartSide
		{
			get { return _startSide; }
			set 
			{ 
				_startSide = value; 
			}
		}

		private ShareCollection			_ownedShares;		// Shares owned by the company.  Empty in 1856.  
		private ShareCollection			_IPOshares;			// Shares still in the IPO.
		private ShareCollection			_openMarketShares;	// Shares in the open market.
		private	TrainCollection			_trains;
		private PrivateCompanies		_aPrivateCompanies;
		private StockMarketPosition		_StockMarketPosition;
		private GameboardHexCollection	_tokenHexes;		// Hexes that this company has tokens at.
		private Hashtable /*MyDictionary<string, HexVisit>*/ _hexVisits;

		public Hashtable /*MyDictionary<string, HexVisit>*/ HexVisits
		{
			get { return _hexVisits; }
		}

		static public string InverseDirection (string sOriginalDirection)
		{
			string	sInverse;

			switch (sOriginalDirection)
			{
				case "N":
					sInverse = "S";
					break;

				case "NE":
					sInverse = "SW";
					break;

				case "SE":
					sInverse = "NW";
					break;

				case "S":
					sInverse = "N";
					break;

				case "SW":
					sInverse = "NE";
					break;

				case "NW":
					sInverse = "SE";
					break;

				default:
					sInverse = "Unrecoverable error";
					GameException	e = new GameException (sInverse);
					throw (e);
			}

			return sInverse;
		}

		private bool BlockedByOtherCompaniesTokens (GameboardHex hex, Side startSide, Side endSide)
		{
			bool		bReturn = true;
			int			nMaxTokens = 0;

			if (hex.TownType == GameboardHex.eTownType.City)
			{
				if (hex.SeperateCities)	// Brown Toronto/ 1830 New York is a special case
				{
					if (hex.Tile != null)
					{
						if (hex.Tile.Color == Tile.eTileColor.Gray)	// Seperated cities are now joined.  Same logic as for merged cities.
						{
							if (hex.City == "Toronto") // Toronto has 4, Hamilton has 3
							{
								nMaxTokens = 4;
							}
							else
							{
								nMaxTokens = 3;
							}

							if (hex.Tokens.Count >= nMaxTokens)  // Do we really need to check for > then?  Probably not.
							{
								foreach (Token token in hex.Tokens)
								{
									if (token.Company.Name == this.Name)
									{
										bReturn = false;
										break;
									}
								}
							}
							else
							{
								bReturn = false;
							}
						}
						else // Green or Brown.
						{
							int		nTokensBlockingThisSide = 0;

							nMaxTokens = 1;

							if ((hex.City == "Toronto") && (hex.Tile.Color == Tile.eTileColor.Brown))	 // Toronto and New York in 1830 have 4 token spots, two per direction.
							{
								nMaxTokens = 2;
							}

							foreach (Token token in hex.Tokens)
							{
								if (token.Company.Name != this.Name)
								{
									if ((token.LocationInHex.GetDirection () == startSide.GetDirection ()) || 
										(token.LocationInHex.GetDirection () == endSide.GetDirection ()))
									{
										nTokensBlockingThisSide++;
									}
								}
							}

							if (nTokensBlockingThisSide < nMaxTokens)
							{
								bReturn = false;
							}
						}
					}
					else	// No cases of blocking if no tiles are laid.  Penn/B&O/C&O/B&M/CPR in 1830 will have to be handled as a special case later.
					{
						bReturn = false;
					}
				}
				else
				{
					if ((hex.Tile == null) || (hex.Tile.Color == Tile.eTileColor.Yellow))
					{
						nMaxTokens = 1;
					}
					else // Brown or Green.  Gray tiles are technically Seperate cities and therefore don't get processed here.
					{
						nMaxTokens = 2;
					}

					if (hex.Tokens.Count >= nMaxTokens)  // Do we really need to check for > then?  Probably not.
					{
						foreach (Token token in hex.Tokens)
						{
							if (token.Company.Name == this.Name)
							{
								bReturn = false;
								break;
							}
						}
					}
					else
					{
						bReturn = false;
					}
				}
			}
			else
			{
				bReturn = false;  // Non city hexes never block.
			}
	
			return bReturn;
		}


		private void AddHexesVisitedFromThisHex (HexVisit currentHexVisit, string sVisitDirection)
		{
			GameboardHex	hex = currentHexVisit.Hex;
			string			sNextHex;
			GameboardHex	nextHex;
			HexVisit		nextHexVisit;
			string			sInverseDirection;

			if (null == hex)
				return;

			if (currentHexVisit.VisitedFromThisDirection (sVisitDirection))	// Has this hex already been visited from this direction?
			{
				return;
			}
			else
			{
				currentHexVisit.DirectionsVisitedFrom.Add (sVisitDirection);
			}

			foreach (Side startSide in hex.ExistingRoutes.Keys)
			{
				if (startSide.GetDirection () == sVisitDirection)
				{
					SideCollection endSides = hex.ExistingRoutes [startSide] as SideCollection;

					foreach (Side endSide in endSides)
					{
						if (!BlockedByOtherCompaniesTokens (hex, startSide, endSide))
						{
							sNextHex = hex.Neighbors [endSide.GetDirection ()] as string;

							if (sNextHex != null)
							{
								nextHex = this.Game.GameboardHexes[sNextHex]; 
								sInverseDirection = InverseDirection (endSide.GetDirection ());

								if (this.HexVisits.ContainsKey (sNextHex)) // See if this hex has already been visited.
								{
									nextHexVisit = this.HexVisits[sNextHex] as HexVisit;
									this.AddHexesVisitedFromThisHex (nextHexVisit, sInverseDirection);	// Process this hex again, this time coming in from the new direction.
								}
								else
								{
									nextHexVisit = new HexVisit ();
									nextHexVisit.Hex = nextHex;
									this.HexVisits.Add (sNextHex, nextHexVisit);
									this.AddHexesVisitedFromThisHex (nextHexVisit, sInverseDirection);
								}
							}	
						}		//  if (!BlockedByOtherCompaniesTokens (startSide, endSide))
					}
				}
			}
		}

		public void CreateHexVisitations ()
		{
			GameboardHex	nextHex;
			string			sNextHex;
			string			sInverseDirection;
			HexVisit		hexVisit; 

			this.HexVisits.Clear ();

			foreach (GameboardHex hex in this.TokenHexes)
			{
				if (this.HexVisits.ContainsKey (hex.Location))	// Have we already visited this hex???  
				{
					hexVisit = this.HexVisits[hex.Location] as HexVisit;
				}
				else
				{
					hexVisit = new HexVisit ();
					hexVisit.Hex = hex;
					this.HexVisits.Add (hex.Location, hexVisit);
				}
				
				if (hex.Tile != null)
				{
				  if (hex.Tile.Name.Equals ("123"))  // Gray Hamilton tile?
				  {
				    if (hex.Tile.TileName.Equals ("Hamilton"))
				    {
				        hex.SeperateCities = false;
				    }
				  }
				} 

				if (hex.SeperateCities) 	
				{
					foreach (Token currentToken in hex.Tokens)
					{
						if (currentToken.Company.Name == this.Name)
						{
							AddHexesVisitedFromThisHex (hexVisit, currentToken.LocationInHex.GetDirection ());

							sNextHex = hex.Neighbors [currentToken.LocationInHex.GetDirection ()] as string;

							if (sNextHex != null)
							{
								nextHex = this.Game.GameboardHexes[sNextHex]; 
								sInverseDirection = InverseDirection (currentToken.LocationInHex.GetDirection ());

								if (this.HexVisits.ContainsKey (sNextHex))	// Has this hex already been visited?  Maybe not from this side... so call AddHexesVisitedFromThisHex anyways.
								{
									HexVisit alreadyVisitedHex = this.HexVisits[sNextHex] as HexVisit;
									this.AddHexesVisitedFromThisHex (alreadyVisitedHex, sInverseDirection);
								}
								else
								{
									HexVisit newHexVisit = new HexVisit ();
									newHexVisit.Hex = nextHex;
									this.HexVisits.Add (nextHex.Location, newHexVisit);
									AddHexesVisitedFromThisHex (newHexVisit, sInverseDirection);
								}
							}
							else	// Hex doesn't have a neighbor in that direction.  This shouldn't be possible.
							{
								GameException	e = new GameException ("Invalid token direction towards nonexistant hex.");
								throw (e);
							}
						}       // if (currentToken.Company.Name == this.Name)
					}			// foreach (Token currentToken in hex.Tokens)
				}				// If SeperateCities
				else // Regular city.   Go out from each direction.
				{
					this.AddHexesVisitedFromThisHex (hexVisit, "N");
					this.AddHexesVisitedFromThisHex (hexVisit, "NW");
					this.AddHexesVisitedFromThisHex (hexVisit, "NE");
					this.AddHexesVisitedFromThisHex (hexVisit, "S");
					this.AddHexesVisitedFromThisHex (hexVisit, "SW");
					this.AddHexesVisitedFromThisHex (hexVisit, "SE");
				}
			}

			if (this.DeferredInitialTokenPlacement)	// No tokens yet.  Hex visitations consists only of the home city.
			{	
				hexVisit = new HexVisit ();
				
				sNextHex = this.Home;
				GameboardHex homeHex = Game.GameboardHexes.Find (sNextHex);

				hexVisit.Hex = homeHex;
				this.HexVisits.Add (homeHex.Location, hexVisit);
			}
		}


		// properties

		//[XmlIgnore]  // TODO  Jeff, set this backpointer up when loading.
		public Game Game
		{
			get
			{
				return _game;
			}
			set
			{
				_game = value;
			}
		}

		public Player Owner
		{
			get
			{
				return _owner;
			}
			set
			{
				_owner = value;
			}
		}

		public string Name
		{
			get
			{
				return _name;
			}
			set
			{
				_name = value;
			}
		}

		public int Cash
		{
			get { return _cash; }
			set { _cash = value; }
		}

        public int LastDividend
		{
            get { return _lastDividend; }
            set { _lastDividend = value; }
		}

        public bool FullShares
        {
            get { return _fullShares; }
            set { _fullShares = value; }
        }

        public bool FullyFunded
        {
            get { return _fullyFunded; }
            set { _fullyFunded = value; }
        }

        public int Escrow
		{
			get { return _escrow; }
			set { _escrow = value; }
		}

        public int ParPrice
		{
			get
			{
				return _parPrice;
			}
			set
			{
				_parPrice = value;
			}
		}

		public int MarketValue
		{
			get
			{
				int nValue	= 0;							// no value yet if not open
				
				if (_StockMarketPosition != null)
					nValue = _StockMarketPosition.Value;	// get current market price

				return nValue;
			}
		}
		public int Loans
		{
			get
			{
				return _loans;
			}
			set
			{
				_loans = value;
			}
		}

		public int Tokens
		{
			get
			{
				return _tokens;
			}
			set
			{
				_tokens = value;
			}
		}

		public int Index
		{
			get
			{
				return _index;
			}
			set
			{
				_index = value;
			}
		}

		public string Home
		{
			get
			{
				return _home;
			}
			set
			{
				_home = value;
			}
		}

		public string Destination
		{
			get
			{
				return _destination;
			}
			set
			{
				_destination = value;
			}
		}

		public int TokensPlayed
		{
			get { return _tokensPlayed; }
			set { _tokensPlayed = value; }
		}

		public bool LoanTaken
		{
			get { return _bLoanTaken; }
			set { _bLoanTaken = value; }
		}

		public bool CanTakeLoan
		{
			get 
			{ 
				int		nSharesHeld	= 10 - (IPOShares.Count + OpenMarketShares.Count);
				bool	bOK	= false;
			
				if (!LoanTaken && Loans < nSharesHeld)
					bOK = true;
 
				return bOK;
			}
		}

		public bool MustRedeemLoans
		{
			get 
			{ 
				int		nSharesHeld	= 10 - (IPOShares.Count + OpenMarketShares.Count);
				bool	bOK	= false;
			
				if (Loans > 0 && Loans > nSharesHeld)
					bOK = true;
 
				return bOK;
			}
		}

		public bool InterestPaid
		{
			get { return _bInterestPaid; }
			set { _bInterestPaid = value; }
		}

		public bool PresidencyBought
		{
			get { return this.IPOShares.Count < 9; }
		}

		public bool Open
		{
			get { return ParPrice != 0; }
		}

		public bool Closed
		{
			get { return StockMarketPosition.Value == 0; }
		}

		public bool Floated		// used in SR to tell if shares can be sold. must have sold shares >= current train showing at SR time
		{
			get { return Operated || ((10 - IPOShares.Count) >= Game.SharesNeededtoOpen); }
		}

		public bool Operated	// has run for first time
		{
			get { return _operated; }
			set { _operated = value; }
		}

		public bool CanOperate	// used in OR to tell if company can run for first time. must have sold shares >= current train showing at OR time when runs first time
		{
			get { return Operated || ((10 - IPOShares.Count) >= Game.SharesNeededtoOpen); }
			set { _canOperate = value; }
		}

		public bool HasARoute
		{
			get { return SeeIfRouteExists (); }
//			set { _hasARoute = value; }		// Do not set, this would be an error.
		}

		public int RunningOrder
		{
			get	{ return _RunningOrder; }
			set { _RunningOrder = value; }
		}

		public bool OperatedThisOperatingRound
		{
			get { return _operatedThisOperatingRound; }
			set { _operatedThisOperatingRound = value; }
		}


        public bool FoldIntoCGR
		{
			get { return _foldIntoCGR; }
			set { _foldIntoCGR = value; }
		}

        public bool FoldIntoCGRActedOn
        {
            get { return _foldIntoCGRActedOn; }
            set { _foldIntoCGRActedOn = value; }
        }

        public string BorrowedTrainName
		{
            get { return _borrowedTrainName; }
            set { _borrowedTrainName = value; }
		}

        public bool BorrowedTrain
        {
            get { return _borrowedTrain; }
            set { _borrowedTrain = value; }
        }

        public bool BorrowingTrain
        {
            get { return _borrowingTrain; }
            set { _borrowingTrain = value; }
        }

        public bool HadPermanantTrain
        {
            get { return _hadPermanantTrain; }
            set { _hadPermanantTrain = value; }
        }

        public bool NeedDestination
		{
			get { return _needDestination; }
			set { _needDestination = value; }
		}

		public bool ReachedDestination
		{
			get 
			{ 
				return _reachedDestination;
			}
			
			set 
			{ 
				_reachedDestination = value;
				
				if (_reachedDestination == true)
				{
					NeedDestination = false;
					
					Cash  += Escrow;	// give escrow $$$ to RR
					Escrow = 0;
				
					Game.History.Add (Name + " reached it's destination.");
				}
			}
		}

		public bool TunnelRights
		{
			get { return _tunnelRights; }
			set { _tunnelRights = value; }
		}

		public bool BridgeRights
		{
			get { return _bridgeRights; }
			set { _bridgeRights = value; }
		}

		public bool PortRights
		{
			get { return _portRights; }
			set { _portRights = value; }
		}

        public bool CompanyAvailable
		{
			get { return _bCompanyAvailable; }
			set { _bCompanyAvailable = value; }
		}

		public PublicCompany ()  // default cons
		{
			_deferredInitialTokenPlacement = false;
			_startSide = new Side ();
			
            ParPrice		= 0;
			Cash			= 0;
            FullShares      = true;
            FullyFunded     = false;
            LastDividend    = 0;
            Escrow			= 0;
			Loans			= 0;
			Tokens			= 0;
			TokensPlayed	= 0;
			this._hasARoute = false;  // Do not change to accessor because of recursion!!!!

            // CGR variables
            BorrowedTrain = false;
            BorrowingTrain = false;
            HadPermanantTrain = false;
            CompanyAvailable = true;
            FoldIntoCGR = false;
            FoldIntoCGRActedOn = false;
            BorrowedTrainName = "";

            // regular variables
            TunnelRights = false;
			BridgeRights = false;
			PortRights = false;
            
			Owner = null;
			Operated = false;
			CanOperate	= false;
            RunningOrder = 0;
			LoanTaken = false;
			InterestPaid = false;
			OperatedThisOperatingRound = false;
			NeedDestination	= true;			// only needed until 5 train showing
			ReachedDestination	= false;	// ""

			_aPrivateCompanies = new PrivateCompanies ();
			StockMarketPosition = null;

			_ownedShares = new ShareCollection ();
			_IPOshares = new ShareCollection ();
			_openMarketShares = new ShareCollection ();
			_tokenHexes = new GameboardHexCollection ();
			_trains = new TrainCollection ();
			_hexVisits = new Hashtable /*MyDictionary<string, HexVisit>*/();
			_startSideSpecified = false;
		}

		public void ResetOperatingRoundRuntimeVariables()	// call at start of every operating round
		{
			OperatedThisOperatingRound = false;
			LoanTaken = false;
			InterestPaid = false;
		}

		// collections
		public GameboardHexCollection TokenHexes
		{
			get { return _tokenHexes; }
		}

		public TrainCollection Trains
		{
			get
			{
				return _trains;
			}
		}

		public ShareCollection IPOShares
		{
			get
			{
				return _IPOshares;
			}
		}

		public ShareCollection OwnedShares
		{
			get
			{
				return _ownedShares;
			}
		}

		public ShareCollection OpenMarketShares
		{
			get
			{
				return _openMarketShares;
			}
		}

		public PrivateCompanies PrivateCompanies
		{
			get
			{
				return _aPrivateCompanies;
			}
		}


		// buy shares
		public void BuyShareFromIPO	(Player buyer, ref bool bPresidency)
		{
			int		nCashNeeded		= ParPrice;
			Share	presidentShare	= null;

			bPresidency = true;

			if (PresidencyBought)
				bPresidency = false;

			if (bPresidency)
				nCashNeeded *= 2;
			
			if (bPresidency)						// if opening a new RR
			{
				foreach (Share share in IPOShares)
				{
					if (share.President)			// find presidents share
					{
						presidentShare = share;
						break;
					}
				}

				IPOShares.Remove (presidentShare);	// remove from IPO
				buyer.Shares.Add (presidentShare);	// give to player
				Owner = buyer;						// set the owner of the company

				// set whether or not destination needed
				if (Game.Trains_4.Count == 0)		// looking at or sold first 5 train so dest not needed
				{
					NeedDestination     = false;
					ReachedDestination  = true;
				}

				// once looking at 6 train, escrow 10 * par price until 6th share sold
				if (Game.Trains_5.Count == 0)		// looking at or sold first 6 train
				{
					Cash	    = 0;
					Escrow	    = 10 * ParPrice;        // escrow $$$ until 6th share purchased
                    FullyFunded = true;
                }
			}
			else									// take any remaining share
			{
				buyer.Shares.Add (IPOShares[0]);	// give to player
				IPOShares.Remove (IPOShares[0]);	// remove from IPO
			}

			// handle cash transfer from player to company cash or company escrow
			buyer.Cash -= nCashNeeded;				// take $$$ from player

            // check if company still opening and 6 shares have not been sold and looking at or sold first 6 train
            if (FullyFunded)   // !Operated && 
			{
                Game.Bank += nCashNeeded;		    // give to bank	

                if (IPOShares.Count <= 4)	// have 6 shares been bought? if so get all escrowed $$$
				{
					Cash      += Escrow;
                    Game.Bank -= Escrow;           // take the $ out of the bank
                    Escrow     = 0;
				}
            }
			else									// else do incremental funding
			{
				// adjust cash if RR needs destination and hasn't reached it yet
				if (IPOShares.Count < 5 && NeedDestination && !ReachedDestination)	// have more than 5 been sold?
					Escrow += nCashNeeded;			// store in escrow
				else if (!FullyFunded)
					Cash += nCashNeeded;			// give to RR if not fully funded	
			    else
                    Game.Bank += nCashNeeded;		// give to bank	
            }
		}

		public void BuyShareFromBank(Player buyer)
		{
			Share	share = OpenMarketShares[0];	// take the first one
			
			OpenMarketShares.Remove(share);			// take from bank
						
			buyer.Shares.Add(share);				// give to the player
						
			buyer.Cash -= MarketValue;				// adjust players cash
			Game.Bank  += MarketValue;
		}
		
		public bool BuyPrivateCompany(Player seller, PrivateCompany company, int nPrice)
		{
			bool	bPurchased	= false;
			
			if (Cash >= nPrice)
			{
				seller.PrivateCompanies.Remove(company);	// remove private from player

				this.PrivateCompanies.Add(company);			// add to RR

				Cash -= nPrice;								// take the cash from the RR
				seller.Cash += nPrice;						// add the cash to the player

				bPurchased = true;

				if (company.Name == "Niagra Falls Suspension Company")
					BridgeRights = true;
				else if (company.Name == "St. Clair Frontier Tunnel Company")
					TunnelRights = true;
			}

			return bPurchased;
		}
		
		public bool	Owns (string sPrivateCompany, ref PrivateCompany returnedCompany)
		{
			bool			bReturn = false;
			
			returnedCompany = null;

			foreach (PrivateCompany privateCompany in this.PrivateCompanies)
			{
				if (privateCompany.Name == sPrivateCompany)
				{
					returnedCompany = privateCompany;
					bReturn = true;
					break;
				}
			}

			return bReturn;
		}

		// operating round handling routines
		public bool TakeOutLoan()
		{
			int		nSharesHeld	= 10 - (IPOShares.Count - OpenMarketShares.Count);
			bool	bOK	= false;
			
			if (!LoanTaken && Loans < nSharesHeld)
			{
				int nLoan = 100;

				if (InterestPaid)	// add 100 if before interest paid
					nLoan = 90;

				_loans++;

				Cash	  += nLoan;
				Game.Bank -= nLoan;

				LoanTaken = true;
				
				bOK	= true;
			}
		
			return bOK;
		}

		public int	RunTrains(out bool bPlayerOwes, out int nAmount)
		{
			return CalculateDividend(out bPlayerOwes, out nAmount);
		}
		
        public void PayDividend(bool bPayout, int nDividend)	// dividend in full value (350 not 35)
		{
            int nPerShareDividend = nDividend / 10;
            
            // dividend must be not 0
            if (bPayout && nDividend > 0)
			{
				if (OpenMarketShares.Count > 0)
				{
                    int nDividendAmount = 0;

                    if (Name != "CGR")
                    {
                        nDividendAmount = OpenMarketShares.Count * nPerShareDividend;
                    }
                    else    // this is CGR so add up share percentages and multiple by dividend 
                    {
                        int nCGRShareTotal = 0;

                        foreach (Share share in OpenMarketShares)
                            nCGRShareTotal += share.Percentage;

                        // calculate full shares
                        nDividendAmount = (nCGRShareTotal / 10) * nPerShareDividend;

                        // do we have half shares?
                        if (nCGRShareTotal % 10 != 0)
                            nDividendAmount += (nPerShareDividend + (nPerShareDividend % 2)) / 2;
                    }

                    Cash      += nDividendAmount;
                    Game.Bank -= nDividendAmount;
				}
				
				// run thru each player and pay them for their shares
				foreach (Player player in Game.Players)
                    player.PayDividend(Index, nPerShareDividend);
				
				AdjustSharePriceAfterPayOut();
			}
			else
			{
				Cash	  += nDividend;
				Game.Bank -= nDividend;

                // if CGR and no permanant (or borrowing) train, "hold" in position
                if (Name == "CGR" && (!HasPermanantTrain() || BorrowingTrain))
                {
                    // make no adjustments...hold in place
                    //AdjustSharePriceAfterPayOut();
                    //AdjustSharePriceAfterHold();
                }
                else
                {
                    AdjustSharePriceAfterHold();
                }
			}

            // mark this as the last payout
            LastDividend = nPerShareDividend;
		}

        public bool ForcedToBuyTrain()
        {
            return (Operated && HasARoute && Trains.Count == 0);
        }

        public void FindCheapestTrain(out bool bBank, out int nTrain, out string sTrain,
			out int cheapestOpenMarketTrain, out int cheapestBankTrain)
        {
            int nTrainCost  = 1000;    // max cost of train to pay (8 or D)
            
            bBank   = false;
            nTrain  = -1;
            sTrain  = "";

            //1. first check open market and find the cheapest
			if (Game.Trains_OpenMarket.Count > 0)
			{
				for (int i = 0; i < Game.Trains_OpenMarket.Count; i++)
				{
					if (Game.Trains_OpenMarket[i].Cost < nTrainCost)
					{
						nTrainCost = Game.Trains_OpenMarket[i].Cost;
						nTrain = i;
					}
				}
				cheapestOpenMarketTrain = nTrainCost;
			}
			else
				cheapestOpenMarketTrain = 9999;

            //2. find bank trains by finding cheapest available
			cheapestBankTrain = 9999;
			if (Game.Trains_2.Count > 0)
			{
				cheapestBankTrain = Game.Trains_2[0].Cost;
				if (Game.Trains_2[0].Cost < nTrainCost)
				{
					sTrain = "2";
					bBank = true;
				}
			}
			else if (Game.Trains_3.Count > 0)
			{
				cheapestBankTrain = Game.Trains_3[0].Cost;
				if (Game.Trains_3[0].Cost < nTrainCost)
				{
					sTrain = "3";
					bBank = true;
				}
			}
			else if (Game.Trains_4.Count > 0)
			{
				cheapestBankTrain = Game.Trains_4[0].Cost;
				if (Game.Trains_4[0].Cost < nTrainCost)
				{
					sTrain = "4";
					bBank = true;
				}
			}
			else if (Game.Trains_5.Count > 0)
			{
				cheapestBankTrain = Game.Trains_5[0].Cost;
				if (Game.Trains_5[0].Cost < nTrainCost)
				{
					sTrain = "5";
					bBank = true;
				}
			}
			else if (Game.Trains_6.Count > 0)
			{
				cheapestBankTrain = Game.Trains_6[0].Cost;
				if (Game.Trains_6[0].Cost < nTrainCost)
				{
					sTrain = "6";
					bBank = true;
				}
			}
			else
			{
				if (Game.MaxTrain8Train)
				{
					if (Game.Trains_8.Count > 0)
					{
						cheapestBankTrain = Game.Trains_8[0].Cost;
						if (Game.Trains_8[0].Cost <= nTrainCost)
						{
							sTrain = "8";
							bBank = true;
						}
					}
				}
				else
				{
					if (Game.Trains_D.Count > 0)
					{
						cheapestBankTrain = Game.Trains_D[0].Cost;
						if (Game.Trains_D[0].Cost <= nTrainCost)
						{
							sTrain = "D";
							bBank = true;
						}
					}
				}
			}
       }
        
		public bool BuyTrain(string sTrain, out string sErrorMsg)
		{
            int             nTrainLimit             = Game.TrainLimit;
            int             nForcedStockSaleAmount  = Game.TrainLimit;
            bool            bPurchased              = false;
            bool            bForcedStockSale        = false;
            bool            bOKToBuyTrain           = false;
            bool            bForcedTrainPurchase    = ForcedToBuyTrain();
            Train           train                   = null;
			TrainCollection	trains                  = Game.GetTrainCollectionFromType(sTrain);
			
			sErrorMsg = "";

			if (Name == "CGR")					// CGR gets +1 for train limit
				nTrainLimit++;
			
			if (Trains.Count < nTrainLimit)		// do I have the slots?
			{
				train = trains[0];				// get the train object

                // do some math here to ensure $ is available to buy train
                if (!bForcedTrainPurchase)
                {
                    if (Cash >= train.Cost)
			            bOKToBuyTrain = true;
                }
                else
                {
                    if (Cash >= train.Cost)                     // check company if has enough money
                    {
                        bOKToBuyTrain = true;
                    }
                    else if (Owner.Cash >= (train.Cost - Cash)) // check if owner can make up difference
                    {
                        int     nCoughAmount = (train.Cost - Cash);
                        string  sMsg;

                        Owner.Cash -= nCoughAmount;
                        Cash       += nCoughAmount;
                        
                        sMsg = Owner.Name + " coughed $" + nCoughAmount.ToString() + " for a train";
                        Game.History.Add(sMsg);
                        
                        bOKToBuyTrain = true;
                    }
                    else                                        // forced stock sale
                    {
                        // 0. transfer all company cash to president (it will be < train cost)
                        Owner.Cash += Cash;
                        Cash        = 0;

                        // we assume the purchase goes thru and redirect to stock round
                        bForcedStockSale        = true;
                        nForcedStockSaleAmount  = train.Cost - Owner.Cash;
                        bOKToBuyTrain           = true;
                    }
               }

                if (bOKToBuyTrain)
				{
                    bool bRemoveTrain = true;

                    if (!bForcedStockSale)
                    {
                        // pay for the train
                        Cash      -= train.Cost;
                        Game.Bank += train.Cost;
                    }
                    else
                    {
                        // take what cash the company has left and force sale the rest
                        Game.Bank += Owner.Cash;
                        Owner.Cash = 0;
                    }

                    // if this is the CGR and it borrowed a train and paying for it, we might not remove it since it already has the train
                    if (Name == "CGR")
                    {
                        if (BorrowingTrain)
                        {
                            // if same train, clean up but don't remove it
                            if (sTrain == BorrowedTrainName)
                            {
                                bRemoveTrain = false;
                            }
                            else    // borrow is different than buying so dump old one
                            {
                                Train           borrowtrain = null;
                                TrainCollection gametrains  = Game.GetTrainCollectionFromType(BorrowedTrainName);

                                borrowtrain = Trains[0];
                                Trains.Remove(borrowtrain);      // remove from RR
                                gametrains.Add(borrowtrain);     // add back into collection
                            }

                            BorrowingTrain      = false;
                            HadPermanantTrain   = true;
                            BorrowedTrainName   = "";
                        }
                    }

                    if (bRemoveTrain)
                    {
                        trains.Remove(train);   // remove from game collection
                        Trains.Add(train);      // add to RR
                    }
                    
                    bPurchased = true;

                    // adjust so when new companies open, they may or may not be able to run based on current train
                    Game.UpdateSharesNeededToOpenOrRunBasedOnCurrentlyAvailableTrain();

                    Game.AdjustGamePhaseInfo(train.Name, train.Rusts);

                    // we have a forced stock sale so handle it
                    if (bForcedStockSale)
                        Game.PerformForcedStockSale(nForcedStockSaleAmount, this);
                }
				else
				{
                    sErrorMsg = Name + " doesn't have enough cash.  It only has $" + Cash.ToString();
				}
			}
			else
			{
				sErrorMsg = Name + " can't purchase the train since it would be over the train limit";
			}

			return bPurchased;
		}
		
        public bool BuyExistingTrain(PublicCompany seller, string sTrain, int nPrice, out string sErrorMsg)
		{
			int		nTrainLimit	            = Game.TrainLimit;
			bool	bPurchased	            = false;
            bool    bForcedTrainPurchase    = ForcedToBuyTrain();
            Train   train                   = null;
			
			sErrorMsg = "";

			if (Name == "CGR")					// CGR gets +1 for train limit
				nTrainLimit++;
			
			if (Trains.Count < nTrainLimit)		// do I have the slots?
			{
				if (Cash >= nPrice)
				{
					Cash		-= nPrice;					// transfer the money for train
					seller.Cash += nPrice;

                    // check if CGR was borrowing a train but bought one from another RR
                    if (Name == "CGR")
                    {
                        if (BorrowingTrain)
                        {
                            // borrow train is different than buying train so dump old one
                            Train           borrowtrain = null;
                            TrainCollection gametrains  = Game.GetTrainCollectionFromType(BorrowedTrainName);

                            borrowtrain = Trains[0];
                            Trains.Remove(borrowtrain);      // remove from RR
                            gametrains.Add(borrowtrain);     // add back into collection

                            BorrowingTrain      = false;
                            HadPermanantTrain   = true;
                            BorrowedTrainName   = "";
                        }
                    }

                    train = seller.GetTrainToSell(sTrain);	// get the train object
                    seller.Trains.Remove(train);			// remove from seller
                    Trains.Add(train);						// add to buyer

                    bPurchased = true;
				}
				else
				{
					sErrorMsg = Name + " doesn't have enough cash.  It only has $" + Cash.ToString();
				}
			}
			else
			{
				sErrorMsg = Name + " can't purchase the train since it would be over the train limit";
			}

			return bPurchased;
		}
		
        public bool BuyOpenMarketTrain(string sTrain, out string sErrorMsg)
		{
			int		nTrainLimit	            = Game.TrainLimit;
            bool    bPurchased              = false;
            bool    bOKToBuyTrain           = false;
            bool    bForcedTrainPurchase    = ForcedToBuyTrain();
            Train   train                   = null;
			
			sErrorMsg = "";

			if (Name == "CGR")					// CGR gets +1 for train limit
				nTrainLimit++;
			
			if (Trains.Count < nTrainLimit)		// do I have the slots?
			{
				foreach (Train omTrain in Game.Trains_OpenMarket)
				{
					if (omTrain.Name == sTrain)
					{
						train = omTrain;
						break;
					}
				}

                // do some fancy math here to ensure $ is available to buy train
                if (!bForcedTrainPurchase)
                {
                    if (Cash >= train.Cost)
                        bOKToBuyTrain = true;
                }
                else
                {
                    if (Cash >= train.Cost)                     // check company if has enough money
                    {
                        bOKToBuyTrain = true;
                    }
                    else if (Owner.Cash >= (train.Cost - Cash)) // check if owner can make up difference
                    {
                        int     nCoughAmount = (train.Cost - Cash);
                        string  sMsg;

                        Owner.Cash -= nCoughAmount;
                        Cash       += nCoughAmount;

                        sMsg = Owner.Name + " coughed $" + nCoughAmount.ToString() + " for a train";
                        Game.History.Add(sMsg);

                        bOKToBuyTrain = true;
                    }
                    else                                        // forced stock sale
                    {
                    }
                }

                if (bOKToBuyTrain)
                {
					Cash	  -= train.Cost;
					Game.Bank += train.Cost;

                    // check if CGR was borrowing a train but bought one from open market
                    if (Name == "CGR")
                    {
                        if (BorrowingTrain)
                        {
                            // borrow train is different than buying train so dump old one
                            Train           borrowtrain = null;
                            TrainCollection gametrains  = Game.GetTrainCollectionFromType(BorrowedTrainName);

                            borrowtrain = Trains[0];
                            Trains.Remove(borrowtrain);      // remove from RR
                            gametrains.Add(borrowtrain);     // add back into collection

                            BorrowingTrain      = false;
                            HadPermanantTrain   = true;
                            BorrowedTrainName   = "";
                        }
                    }

                    Game.Trains_OpenMarket.Remove(train);	// remove from game collection
                    Trains.Add(train);

                    bPurchased = true;
				}
				else
				{
					sErrorMsg = Name + " doesn't have enough cash.  It only has $" + Cash.ToString();
				}
			}
			else
			{
				sErrorMsg = Name + " can't purchase the train since it would be over the train limit";
			}

			return bPurchased;
		}
		
        public bool TradeInTrain(string sTrain, out string sErrorMsg)
		{
			int		nTrainCost      = -1;
			int		nTrainLimit		= Game.TrainLimit;
			bool	bPurchased		= false;
			string	sTradedTrain	= "D";
            Train   tradinTrain     = null;

			sErrorMsg = "";
			
			if (Name == "CGR")					// CGR gets +1 for train limit
				nTrainLimit++;
			
			if (Game.MaxTrain8Train)
				sTradedTrain = "8";
			
            foreach (Train companyTrain in Trains)
            {
                if (companyTrain.Name == sTrain)
                {
                    if (Game.MaxTrain8Train)
                        nTrainCost = companyTrain.TradeUpTo8Cost;
                    else
                        nTrainCost = companyTrain.TradeUpToDCost;

                    tradinTrain = companyTrain;
                    break;
                }
            }

			if (Trains.Count <= nTrainLimit)	    // do I have the slots?
			{
                if (Cash >= nTrainCost)
				{
                    Train           newTrain;
                    TrainCollection gameTrains = Game.GetTrainCollectionFromType(sTradedTrain);

                    Cash      -= nTrainCost;
					Game.Bank += nTrainCost;

                    // remove the tradein train from the RR and put into open market
                    Trains.Remove(tradinTrain);
                    Game.Trains_OpenMarket.Add(tradinTrain);
                    
                    // take tradeup train from collection and add to company
                    newTrain = gameTrains[0];
                    gameTrains.Remove(newTrain);
                    Trains.Add(newTrain);

					bPurchased = true;

                    Game.AdjustGamePhaseInfo(newTrain.Name, newTrain.Rusts);
				}
				else
				{
					sErrorMsg = Name + " doesn't have enough cash.  It only has $" + Cash.ToString();
				}
			}
			else
			{
				sErrorMsg = Name + " can't purchase the train since it would be over the train limit";
			}

			return bPurchased;
		}
		
        public void RustTrains(string sTrainToRust)
		{
			int	nTrains	= Trains.Count - 1;

			while (nTrains >= 0)
			{
				Train	train = Trains[nTrains];	// get a train

				if (train.Name == sTrainToRust)
					Trains.Remove(train);

				nTrains--;
			}
		}
		
        public void ReduceCompanyTrainLimits()
		{
			// TODO should prompt player for train to dump into open market
			// but for now remove the trains in increasing order 2, 3, ...
			if (Trains.Count > Game.TrainLimit)
			{
				if (Game.TrainLimit == 3)		// 4 was just bought
				{
					// dump a 3
					foreach (Train train in Trains)
					{
						if (train.Name == "3")
						{
							Trains.Remove(train);
							Game.Trains_OpenMarket.Add(train);
							break;
						}
					}
				}
				else if (Game.TrainLimit == 2)	// 5 was just bought
				{
					bool bFound3 = false;
					
					// dump a 3
					foreach (Train train in Trains)
					{
						if (train.Name == "3")
						{
							Trains.Remove(train);
							Game.Trains_OpenMarket.Add(train);
							bFound3 = true;
							break;
						}
					}

					// if no 3's, dump a 4
					if (!bFound3)
					{
						foreach (Train train in Trains)
						{
							if (train.Name == "4")
							{
								Trains.Remove(train);
								Game.Trains_OpenMarket.Add(train);
								break;
							}
						}
					}
				}
			}
		}
		public bool RepayLoan()
		{
			bool	bOK	= false;
			
			if (Loans > 0 && Cash >= 100)	// cant repay loans we don't have
			{
				Loans--;

				Cash	  -= 100;
				Game.Bank += 100;

				bOK	= true;
			}
		
			return bOK;
		}

		public void ClosePrivateCompanies()
		{
/*		JWF 11.9.2007  This may not work if more than 1 private is owned.
			for (int i = 0; i < PrivateCompanies.Count; i++)
			{
				PrivateCompany company	= PrivateCompanies[0];
	
				PrivateCompanies.Remove(company);
			}
 */

            for (int i = PrivateCompanies.Count - 1; i >= 0; i--)
            {
                PrivateCompany company = PrivateCompanies[i];

                PrivateCompanies.Remove(company);
            }			
		}
        

		private int CalculateDividend(out bool bPlayerOwes, out int nAmount)	// call to figure out how much RR will run for
		{
			int nDividend	= 0;
			int nInterest	= PayInterest();

			InterestPaid    = true;
			bPlayerOwes     = false;
			nAmount         = 0;

			nDividend = CalculateRoutes();	// what will the RR run for? 

			if (nInterest > 0)
			{
				if (nDividend > nInterest)
				{
					nDividend -= nInterest;	// reduce payout by interest amount (if any)
				}
				else
				{
					nAmount     = nInterest - nDividend;
					bPlayerOwes = true;
					nDividend   = 0;
				}
			}

			return nDividend;
		}
		
		private int CalculateRoutes()
		{
			RouteCollection routes = RouteCollection.FindBestRoutes (this, Trains);
			string test = routes.ToString ();
			return routes.TotalValue;
		}

		private int PayInterest()
		{
			int nInterestDue = 0;

			if (Loans > 0)
			{
				int     nLoans = Loans;
                string  sMsg;
				
				nInterestDue = Loans * 10;
			
				while (Cash - 10 >= 0 && nLoans > 0)
				{
					Cash	  -= 10;
					Game.Bank += 10;

					nInterestDue -= 10;
					nLoans--;
				}
                
                sMsg = Name + " paid $" + ((Loans - nLoans) * 10).ToString() + " in interest";
                Game.History.Add(sMsg);
            }

			return nInterestDue;
		}

		public Train GetTrainToSell(string sTrain)
		{
			foreach (Train train in Trains)
			{
				if (train.Name == sTrain)
					return train;
			}

			return null;
		}

        public bool HasPermanantTrain()
        {
            bool bPermanant = false;

            foreach (Train train in Trains)
            {
                if (train.Name == "5" || train.Name == "6" || train.Name == "8" || train.Name == "D")
                    bPermanant = true;
            }

            return bPermanant;
        }

		// stock market manipluation
		public StockMarketPosition StockMarketPosition
		{
			get { return _StockMarketPosition; }
			set { _StockMarketPosition = value; }
		}

		public void SetInitialStockMarketPosition()
		{
			switch (ParPrice)
			{
				case 100:
					StockMarketPosition = Game.StockMarketPositions["A5"];
					break;
						
				case 90:
					StockMarketPosition = Game.StockMarketPositions["B5"];
					break;
						
				case 80:
					StockMarketPosition = Game.StockMarketPositions["C5"];
					break;
						
				case 75:
					StockMarketPosition = Game.StockMarketPositions["D5"];
					break;
						
				case 70:
					StockMarketPosition = Game.StockMarketPositions["E5"];
					break;
						
				case 65:
					StockMarketPosition = Game.StockMarketPositions["F5"];
					break;
			}

			RunningOrder = StockMarketPosition.RunningOrder++;	// get running order
		}

		public void AdjustSharePriceAfterStockRound()
		{
			if (IPOShares.Count == 0 && OpenMarketShares.Count == 0)	// are all share sold out?
				AdjustSharePrice(eStockAction.SoldOut);
		}
		
        public void AdjustSharePriceAfterSale(int nSharesSold)
		{
            // if this is the CGR and doesn't have a permanant train then share sale doesn't drop stock price
            if (Name == "CGR" && !HasPermanantTrain())
                return;
            
            int nSharesToSell = nSharesSold;

            // with CGR, must only drop 1 row per 10% share sold
            if (!FullShares)
                nSharesToSell = nSharesSold / 2;

            for (int i = 0; i < nSharesToSell; i++)
                AdjustSharePrice(eStockAction.Sold);

			if (Closed)
				CloseCompany(true);
		}
		
        public void AdjustSharePriceAfterPayOut()
		{
			AdjustSharePrice(eStockAction.PayOut);
		}
		
        public void AdjustSharePriceAfterHold()
		{
			AdjustSharePrice(eStockAction.Hold);

            // don't do this or it causes major problems in OR
            //if (Closed)
            //    CloseCompany(true);
        }

		private void AdjustSharePrice(eStockAction action)
		{
			if (StockMarketPosition != null)
			{
                string sCurLocation = StockMarketPosition.Location;
                string sNewLocation = sCurLocation;
			
				if (Name == "CGR")
				{
					if (action == eStockAction.Hold || action == eStockAction.Sold)
					{
						if (action == eStockAction.Hold)
							sNewLocation = StockMarketPosition.HoldLocation;
						else if (action == eStockAction.Sold)
							sNewLocation = StockMarketPosition.SoldLocation;
					
						if (Game.StockMarketPositions[sNewLocation].Value == 0)	// CGR can't enter the closed area
							return;
					}
				}
				
				switch (action)
				{
					case eStockAction.PayOut:
						sNewLocation = StockMarketPosition.PayOutLocation;
						break;
				
					case eStockAction.Hold:
						sNewLocation = StockMarketPosition.HoldLocation;
						break;
				
					case eStockAction.SoldOut:
						sNewLocation = StockMarketPosition.SoldOutLocation;
						break;
				
					case eStockAction.Sold:
						sNewLocation = StockMarketPosition.SoldLocation;
						break;
				}
			
                // if we didn't move on stock market (ie sold out at top row or sold down on botton row), keep same position and running order
                if (sCurLocation != sNewLocation)
                {
                    StockMarketPosition.RunningOrder--;	                // leaving so dec count
                    StockMarketPosition = Game.StockMarketPositions[sNewLocation];
                    RunningOrder = StockMarketPosition.RunningOrder++;	// get running order
                }
			}
		}

		public void CloseCompany(bool bRemoveNow)
		{
			// check if company should be closed
			if (Closed && CompanyAvailable)		// closed area reached
			{
				// transfer all cash to bank
				Game.Bank += Cash;
				Game.Bank += Escrow;

                Cash = 0;
                Loans = 0;
                
                // close any privates owned
				ClosePrivateCompanies();

				// remove all IPO stock
				while (IPOShares.Count > 0)
					IPOShares.Remove(IPOShares[0]);

				// remove all open market stock
				while (OpenMarketShares.Count > 0)
					OpenMarketShares.Remove(OpenMarketShares[0]);
				
				// remove all player stock
				foreach (Player player in Game.Players)
					player.ClosePublicCompany(Index);

				// remove trains and put into open market
				while (Trains.Count > 0)
				{
					Train	train	= Trains[0];

					Trains.Remove(train);				// remove train from company
					Game.Trains_OpenMarket.Add(train);	// add train to open market pool
				}
				
				if (bRemoveNow)							// only remove company from game list during a SR
				{
					string sMsg;
							
					sMsg = "The " + Name + " has been closed";
					Game.History.Add(sMsg);
					//Game.PublicCompanies.Remove(this);
                    Game.PublicCompanies[Index].CompanyAvailable = false;
                }
			}
		}

		public void CollapseCompanyIntoCGR(PublicCompany cgr)
		{
			// transfer any cash
			cgr.Cash += Cash;

            Cash    = 0;
            Loans   = 0;

			// transfer trains to cgr
			while (Trains.Count > 0)
			{
				Train	train	= Trains[0];

				Trains.Remove(train);	// remove train from company
				cgr.Trains.Add(train);	// add train to cgr
			}

			// TODO transfer tunnel and/or bridge

			// remove all IPO stock
			while (IPOShares.Count > 0)
				IPOShares.Remove(IPOShares[0]);

			// remove all open market stock
			while (OpenMarketShares.Count > 0)
				OpenMarketShares.Remove(OpenMarketShares[0]);
				
			// remove all player stock
			foreach (Player player in Game.Players)
				player.ClosePublicCompany(Index);

			string sMsg;
					
			sMsg = "The " + Name + " has been folded into the CGR";
			Game.History.Add(sMsg);
			//Game.PublicCompanies.Remove(this);
            CompanyAvailable = false;
        }

		private void CheckHexesVisitedFromThisHex (HexVisit currentHexVisit, string sVisitDirection)
		{
			GameboardHex	hex = currentHexVisit.Hex;
			string			sNextHex;
			GameboardHex	nextHex;
			HexVisit		nextHexVisit;
			string			sInverseDirection;

			if (null == hex)
				return;

			if (!this.NeedDestination)
				return;

			if (currentHexVisit.VisitedFromThisDirection (sVisitDirection))	// Has this hex already been visited from this direction?
			{
				return;
			}
			else
			{
				currentHexVisit.DirectionsVisitedFrom.Add (sVisitDirection);
			}

			if (hex.HexType == GameboardHex.eHexType.OffBoard)
			{
				if (hex.Location == this.Destination)
				{
					this.ReachedDestination = true;
				}

				return;
			}

			foreach (Side startSide in hex.ExistingRoutes.Keys)
			{
				// Are we at the destination hex?  And if so, is there track in the destination hex that connects to existing track?
				if (hex.Location == this.Destination)
				{
					if (currentHexVisit.DirectionsVisitedFrom.Contains (startSide.GetDirection ()))
					{
						this.ReachedDestination = true;
						break;
					}
				}

				if (startSide.GetDirection () == sVisitDirection)
				{
					SideCollection endSides = hex.ExistingRoutes [startSide] as SideCollection;

					foreach (Side endSide in endSides)
					{
						sNextHex = hex.Neighbors [endSide.GetDirection ()] as string;

						if (sNextHex != null)
						{
							nextHex = this.Game.GameboardHexes[sNextHex]; 
							sInverseDirection = InverseDirection (endSide.GetDirection ());

							if (this.HexVisits.ContainsKey (sNextHex)) // See if this hex has already been visited.
							{
								nextHexVisit = this.HexVisits[sNextHex] as HexVisit;
								this.CheckHexesVisitedFromThisHex (nextHexVisit, sInverseDirection);	// Process this hex again, this time coming in from the new direction.
							}
							else
							{
								nextHexVisit = new HexVisit ();
								nextHexVisit.Hex = nextHex;
								this.HexVisits.Add (sNextHex, nextHexVisit);
								this.CheckHexesVisitedFromThisHex (nextHexVisit, sInverseDirection);
							}
						}	
					}
				}
			}
		}

		private void CheckHexesVisitedFromThisHexForRoute (HexVisit currentHexVisit, string sVisitDirection)
		{
			GameboardHex	hex = currentHexVisit.Hex;
			string			sNextHex;
			GameboardHex	nextHex;
			HexVisit		nextHexVisit;
			string			sInverseDirection;

			if ((null == hex) || this._hasARoute) // Do not change to accessor because of recursion!!!!
				return;

			if (currentHexVisit.VisitedFromThisDirection (sVisitDirection))	// Has this hex already been visited from this direction?
			{
				return;
			}
			else
			{
				currentHexVisit.DirectionsVisitedFrom.Add (sVisitDirection);
			}

			if (hex.Value > 0)
			{
				if (hex.Location == this._startOfRoute.Hex.Location)	// This is the starting hex.  The only way this is a route is if seperate cities.
				{
					if (hex.SeperateCities)
					{
						if ( !_startOfRoute.DirectionsVisitedFrom.Contains (sVisitDirection))
						{
							foreach (Side startSide in hex.ExistingRoutes.Keys)
							{
								if (startSide.GetDirection () == sVisitDirection)
								{
									this._hasARoute = true; // Do not change to accessor because of recursion!!!!

									foreach (Side endSide in hex.ExistingRoutes[startSide] as SideCollection)
									{
										if (_startOfRoute.DirectionsVisitedFrom.Contains (endSide.GetDirection ()))
										{
											this._hasARoute = false; // Do not change to accessor because of recursion!!!!
											break;
										}
									}

									break;
								}
							}
						}
					}
				}
				else	// Visiting a new hex with a value.  It's a route if there is track connecting to the side we are visiting from or if it's an offboard location.
				{
					if (hex.HexType == GameboardHex.eHexType.OffBoard)
					{
						this._hasARoute = true; // Do not change to accessor because of recursion!!!!
						return;
					}
					else
					{
						foreach (Side startSide in hex.ExistingRoutes.Keys)
						{
							if (startSide.GetDirection () == sVisitDirection)
							{
								this._hasARoute = true; // Do not change to accessor because of recursion!!!!
								return;
							}
						}
					}
				}
			}

// Now check hexes visited from this hex for routes.

			foreach (Side startSide in hex.ExistingRoutes.Keys)
			{
				if (startSide.GetDirection () == sVisitDirection)
				{
					SideCollection endSides = hex.ExistingRoutes [startSide] as SideCollection;

					foreach (Side endSide in endSides)
					{
						sNextHex = hex.Neighbors [endSide.GetDirection ()] as string;

						if (sNextHex != null)
						{
							nextHex = this.Game.GameboardHexes[sNextHex]; 
							sInverseDirection = InverseDirection (endSide.GetDirection ());

							if (this.HexVisits.ContainsKey (sNextHex)) // See if this hex has already been visited.
							{
								nextHexVisit = this.HexVisits[sNextHex] as HexVisit;
								this.CheckHexesVisitedFromThisHexForRoute (nextHexVisit, sInverseDirection);	// Process this hex again, this time coming in from the new direction.
							}
							else
							{
								nextHexVisit = new HexVisit ();
								nextHexVisit.Hex = nextHex;
								this.HexVisits.Add (sNextHex, nextHexVisit);
								this.CheckHexesVisitedFromThisHexForRoute (nextHexVisit, sInverseDirection);
							}
						}	
					}
				}
			}
		}

		public bool SeeIfRouteExists ()
		{
			bool			bReturn = false;
			GameboardHex	nextHex;
			string			sNextHex;
			string			sInverseDirection;
			HexVisit		hexVisit; 

			this.HexVisits.Clear ();
			this._hasARoute = false;		// Route's may disappear if due to downgrades. // Do not change to accessor because of recursion!!!!

			foreach (GameboardHex hex in this.TokenHexes)
			{
				if (!this._hasARoute)	// Do not change to accessor because of recursion!!!!
				{
					hexVisit = new HexVisit ();
					hexVisit.Hex = hex;
					this.HexVisits.Add (hex.Location, hexVisit);

					this._startOfRoute = new HexVisit ();
					this._startOfRoute.Hex = hex;

					if (hex.SeperateCities)
					{
						foreach (Token currentToken in hex.Tokens)
						{
							if (currentToken.Company.Name == this.Name)
							{
								this._startOfRoute.DirectionsVisitedFrom.Add (currentToken.LocationInHex.GetDirection ());
								CheckHexesVisitedFromThisHexForRoute (hexVisit, currentToken.LocationInHex.GetDirection ());
								sNextHex = hex.Neighbors [currentToken.LocationInHex.GetDirection ()] as string;

								if (sNextHex != null)
								{
									nextHex = this.Game.GameboardHexes[sNextHex]; 
									sInverseDirection = InverseDirection (currentToken.LocationInHex.GetDirection ());

									if (this.HexVisits.ContainsKey (sNextHex))	// Has this hex already been visited?  Maybe not from this side... so call CheckHexesVisitedFromThisHexForRoute anyways.
									{
										HexVisit alreadyVisitedHex = this.HexVisits[sNextHex] as HexVisit;
										this.CheckHexesVisitedFromThisHexForRoute (alreadyVisitedHex, sInverseDirection);
									}
									else
									{
										HexVisit newHexVisit = new HexVisit ();
										newHexVisit.Hex = nextHex;
										this.HexVisits.Add (nextHex.Location, newHexVisit);
										CheckHexesVisitedFromThisHexForRoute (newHexVisit, sInverseDirection);
									}
								}
								else	// Hex doesn't have a neighbor in that direction.  This shouldn't be possible.
								{
									GameException	e = new GameException ("Invalid token direction towards nonexistant hex.");
									throw (e);
								}
							}       // if (currentToken.Company.Name == this.Name)
						}			// foreach (Token currentToken in hex.Tokens)
					}				// If SeperateCities
					else // Regular city.   Go out from each direction.
					{
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "N");
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "NW");
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "NE");
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "S");
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "SW");
						this.CheckHexesVisitedFromThisHexForRoute (hexVisit, "SE");
					}
				}
			}

			bReturn = this._hasARoute;	// Do not change to accessor because of recursion!!!!
			return bReturn;
		}

		public void CheckForDestination ()
		{
			if (this.NeedDestination)
			{
				GameboardHex	nextHex;
				string			sNextHex;
				string			sInverseDirection;
				HexVisit		hexVisit; 

				this.HexVisits.Clear ();

				foreach (GameboardHex hex in this.TokenHexes)
				{
					if (hex.Location == this.Home)
					{
						hexVisit = new HexVisit ();
						hexVisit.Hex = hex;
						this.HexVisits.Add (hex.Location, hexVisit);

						if (hex.SeperateCities)
						{
							foreach (Token currentToken in hex.Tokens)
							{
								if (currentToken.Company.Name == this.Name)
								{
									CheckHexesVisitedFromThisHex (hexVisit, currentToken.LocationInHex.GetDirection ());

									sNextHex = hex.Neighbors [currentToken.LocationInHex.GetDirection ()] as string;

									if (sNextHex != null)
									{
										nextHex = this.Game.GameboardHexes[sNextHex]; 
										sInverseDirection = InverseDirection (currentToken.LocationInHex.GetDirection ());

										if (this.HexVisits.ContainsKey (sNextHex))	// Has this hex already been visited?  Maybe not from this side... so call CheckHexesVisitedFromThisHex anyways.
										{
											HexVisit alreadyVisitedHex = this.HexVisits[sNextHex] as HexVisit;
											this.CheckHexesVisitedFromThisHex (alreadyVisitedHex, sInverseDirection);
										}
										else
										{
											HexVisit newHexVisit = new HexVisit ();
											newHexVisit.Hex = nextHex;
											this.HexVisits.Add (nextHex.Location, newHexVisit);
											CheckHexesVisitedFromThisHex (newHexVisit, sInverseDirection);
										}
									}
									else	// Hex doesn't have a neighbor in that direction.  This shouldn't be possible.
									{
										GameException	e = new GameException ("Invalid token direction towards nonexistant hex.");
										throw (e);
									}
								}       // if (currentToken.Company.Name == this.Name)
							}			// foreach (Token currentToken in hex.Tokens)
						}				// If SeperateCities
						else // Regular city.   Go out from each direction.
						{
							this.CheckHexesVisitedFromThisHex (hexVisit, "N");
							this.CheckHexesVisitedFromThisHex (hexVisit, "NW");
							this.CheckHexesVisitedFromThisHex (hexVisit, "NE");
							this.CheckHexesVisitedFromThisHex (hexVisit, "S");
							this.CheckHexesVisitedFromThisHex (hexVisit, "SW");
							this.CheckHexesVisitedFromThisHex (hexVisit, "SE");
						}
					}
				}
			}
		}
	}
}

